package cn.jingdalei.user.service.impl;

import cn.jingdalei.basic.exception.BusinessException;
import cn.jingdalei.basic.util.*;
import cn.jingdalei.user.constant.UserContants;
import cn.jingdalei.user.domain.*;
import cn.jingdalei.user.mapper.LogininfoMapper;
import cn.jingdalei.user.mapper.UserMapper;
import cn.jingdalei.user.mapper.WxUserMapper;
import cn.jingdalei.user.service.ILoginService;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements ILoginService {

    @Autowired
    private LogininfoMapper logininfoMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private WxUserMapper wxUserMapper;

    @Autowired
    private UserMapper UserMapper;

    /**
     * 主站登录
     * @param loginDto
     * @return
     */
    @Override
    public Map<String, Object> loginAccount(LoginDto loginDto) {

        // 校验
        // 1. 参数非空
        if(StringUtils.isEmpty(loginDto.getUsername())
                || StringUtils.isEmpty(loginDto.getPassword())
                || StringUtils.isEmpty(loginDto.getType())){
            throw new BusinessException("用户名或密码错误");
        }
        // 2. 用户是否存在
        Logininfo logininfo = logininfoMapper.loadByLoginDto(loginDto);
        if(logininfo == null){
            throw new BusinessException("用户名或密码错误");
        }
        // 3. 状态是否可用 默认激活
        // 校验通过--》密码比对
        String stal = logininfo.getSalt();
        String pwdTmp = MD5Utils.encrypByMd5(loginDto.getPassword() + stal);
        if(!pwdTmp.equals(logininfo.getPassword())){
            throw new BusinessException("用户名或密码错误");
        }
       /* // 保存logininfo 生产token作为key 设置30分钟后过期
        // 获取token
        String token = UUID.randomUUID().toString();
        // 对象需要序列化
        redisTemplate.opsForValue().set(token, logininfo,
                30, TimeUnit.MINUTES);

        // 如果登录成功，还需要返回token和loginInfo 用map来装
        Map<String, Object> map = new HashMap<>();
        //将需要返回的添加到map
        map.put("token", token);
        // 为了安全将密码和盐值设置为空
        logininfo.setPassword(null);
        logininfo.setSalt(null);
        map.put("logininfo", logininfo);
        return map;*/
       return freeLogin(logininfo);
    }

    /**
     * 微信登录
     * @param param
     * @return
     */
    @Override
    public AjaxResult wechat(Map<String, String> param) {
        // 1.微信授权获取code
        String code = param.get("code");
        // 校验
        if (!StringUtils.hasLength(code)){// 1.判断code非空
            throw new BusinessException("没有获取授权码");
        }
// api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
        String getTokenUrl = UserContants.WXUSER_GET_TOKEN_URL
                .replace("APPID", UserContants.APPID)
                .replace("SECRET", UserContants.SECRET)
                .replace("CODE", code);
        // 2. 根据code通过工具类获取token
        String tokenObjStr = HttpClientUtils.httpGet(getTokenUrl);
        // 3. 通过工具类在后端代码中将json字符串转换为json对象
        JSONObject jsonObj = JSONObject.parseObject(tokenObjStr);
        String accessToken = jsonObj.getString("access_token");// 令牌
        String openId = jsonObj.getString("openid");// 微信号
        // 4.判断openId是已经存在（查询t_wxUser）
        WxUser wxUser = wxUserMapper.loadByOpenId(openId);
        // 判断微信用户是否已经存在了且已经注册了
        if(wxUser!=null && wxUser.getUser_id()!=null){
            // 注册了就直接免密登录
            // 连表查询出logininfo
            Logininfo logininfo = logininfoMapper.loadByUserId(wxUser.getUser_id());
            return AjaxResult.me().setResultObj(freeLogin(logininfo));
        } else {
            // 5.找不到用户 跳转到绑定页面 并携带 Token 和 openId
            // 最终返回的 success是false
            String binderUrlParam = "?accessToken="+accessToken+"&openId="+openId;
            return AjaxResult.me().setSuccess(false).setResultObj(binderUrlParam);
        }
    }

    /**
     * 第一次扫码登录用户绑定  service业务流
     * @param binderDto
     * @return
     */
    @Override
    public AjaxResult binder(BinderDto binderDto) {

        // 一：校验
        // 1.空校验 phone verifyCode accessToken openId 都不能为空
        if(!StringUtils.hasLength(binderDto.getPhone())
           || !StringUtils.hasLength(binderDto.getVerifyCode())
           || !StringUtils.hasLength(binderDto.getAccessToken())
           || !StringUtils.hasLength(binderDto.getOpenId())){
            throw new BusinessException("请填写完整信息");
        }
        // 2.判断验证码
        Object verifyCode = redisTemplate.opsForValue()
                .get(UserContants.BUSINESS_BINDER_PREFIX + binderDto.getPhone());
        if(verifyCode==null){
            throw new BusinessException("验证码已失效，请重新发送");
        }
        String code = verifyCode.toString().split(":")[0];
        if(!code.equalsIgnoreCase(binderDto.getVerifyCode())){
            throw new BusinessException("验证码输入错误，请重新输入");
        }
        // 二：判断phone是否被注册 user
        User userTmp = UserMapper.loadByPhone(binderDto.getPhone());
        User user = null;
        Logininfo logininfo = null;
        if(userTmp!=null){// 1.如果注册了，那么我们可以直接绑定微信用户了
            user = userTmp;
            logininfo = logininfoMapper.loadById(user.getLogininfo_id());
        } else {
            // 2.如果没有注册过，生成t_user + t_loginInfo
            user = initUser(binderDto);
            logininfo = user2logininfo(user);
            // 保存信息
            logininfoMapper.save(logininfo);
            user.setLogininfo_id(logininfo.getId());
            UserMapper.save(user);
        }
            // 三：通过 token+openId 查询微信信息 wxuser         ③
            String getUserUrl = UserContants.WXUSER_GET_USER_URL
                    .replace("ACCESS_TOKEN", binderDto.getAccessToken())
                    .replace("OPENID", binderDto.getOpenId());
            // json字符串 需要转换才能获取其中的参数
            String tokenStr = HttpClientUtils.httpGet(getUserUrl);
            // 获取tokenStr中的数据生成wxuser表，并绑定user
            WxUser wxUser = initWxUser(tokenStr,user);
            wxUserMapper.save(wxUser);
            // 五：免密登录
        //  freeLogin(logininfo);
        // return AjaxResult.me().setResultObj(map);
        Map<String, Object> map = freeLogin(logininfo);
        return AjaxResult.me().setResultObj(map);
    }

    private WxUser initWxUser(String tokenStr, User user) {
        WxUser wxUser = new WxUser();
        JSONObject jsonObj = JSONObject.parseObject(tokenStr);
        wxUser.setUser_id(user.getId());
        wxUser.setOpenid(jsonObj.getString("openid"));// 微信号
        String nickname = jsonObj.getString("nickname");
        try{
            //进行编码
            nickname =  Base64.encodeBase64String(nickname.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        wxUser.setNickname(nickname); // 别名

        wxUser.setSex(jsonObj.getInteger("sex"));//性别
        wxUser.setHeadimgurl(jsonObj.getString("headimgurl")); // 头像
        String province = jsonObj.getString("province");
        String city = jsonObj.getString("city");
        wxUser.setAddress(province+city);// 地址
        wxUser.setUnionid(jsonObj.getString("unionid")); // 工会
        return wxUser;
    }

    private Logininfo user2logininfo(User user) {
        Logininfo logininfo = new Logininfo();
        // 属性复制
        BeanUtils.copyProperties(user, logininfo);
        logininfo.setType(1);
        return logininfo;
    }

    private User initUser(BinderDto binderDto) {
        // 创建返回的对象
        User user = new User();
        // 转换数据
        user.setUsername(binderDto.getPhone());
        user.setPhone(binderDto.getPhone());
        // 获取盐值
        String stal = StrUtils.getComplexRandomString(32);
        // 拼接密码 生成随机密码
        String stalPwd = MD5Utils.encrypByMd5("1" + stal);
        user.setSalt(stal);
        user.setPassword(stalPwd);
        return user;
    }

    /**
     * 免密登录方法
     * @param logininfo
     * @return
     */
    public Map<String, Object> freeLogin(Logininfo logininfo){
        // 注册了就直接免密登录
        // 保存logininfo 生产token作为key 设置30分钟后过期
        // 获取token
        String token = UUID.randomUUID().toString();
        // 对象需要序列化
        redisTemplate.opsForValue().set(token, logininfo,
                30, TimeUnit.MINUTES);

        // 如果登录成功，还需要返回token和loginInfo 用map来装
        Map<String, Object> map = new HashMap<>();
        //将需要返回的添加到map
        map.put("token", token);
        // 为了安全将密码和盐值设置为空
        logininfo.setPassword(null);
        logininfo.setSalt(null);
        map.put("logininfo", logininfo);
        // 最终返回的 success是true
       return map;
    }
}
